/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gui.model;

import gui.data.ITrackCellData;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

/**
 * A filterable listModel
 * 
 * @author Pascal
 */
public class TrackFilterableListDataModel extends ArrayList<ITrackCellData> implements ListModel<ITrackCellData> {

    private List<ListDataListener> dataListeners;
    private String filter;
    
    private List<ITrackCellData> filtered;
    
    public TrackFilterableListDataModel(String filter) {
        dataListeners = new LinkedList<>();
        
        filtered = new ArrayList<>();
        setFilter(filter);
    }
    
    public TrackFilterableListDataModel() {
        this(null);
    }
    
    @Override
    public boolean remove(Object o) {
        int i = super.indexOf(o);
        boolean success = super.remove(o);
        
        if (success) {
            notifyListeners(ListDataEvent.INTERVAL_REMOVED, i, i);
        }
        
        return success;
    }
    
    @Override
    public ITrackCellData remove(int index) {
        ITrackCellData e = super.remove(index);
        
        notifyListeners(ListDataEvent.INTERVAL_REMOVED, index, index);
        
        return e;
    }
    
    @Override
    public boolean removeAll(Collection<?> c) {
        if (!c.isEmpty()) {
            int begin = super.indexOf(c.toArray()[0]);
            boolean success = super.removeAll(c);

            if (success) {
                notifyListeners(ListDataEvent.INTERVAL_REMOVED, begin, begin + c.size());
            }

            return success;
        }
        else {
            return false;
        }
    }
    
    @Override
    public ITrackCellData set(int index, ITrackCellData e) {
        ITrackCellData el = super.set(index, e);
        
        notifyListeners(ListDataEvent.CONTENTS_CHANGED, index, index);
        
        return el;
    }
    
    @Override
    public void clear() {
        int sizeBefore = size();
        super.clear();
        
        notifyListeners(ListDataEvent.INTERVAL_REMOVED, 0, sizeBefore - 1);
    }
    
    @Override
    public boolean add(ITrackCellData e) {
        boolean success = super.add(e);
        
        if (success) {
            notifyListeners(ListDataEvent.INTERVAL_ADDED, size() - 1, size() - 1);
        }
        
        return success;
    }
    
    @Override
    public void add(int index, ITrackCellData e) {
        super.add(index, e);
        
        notifyListeners(ListDataEvent.INTERVAL_ADDED, index, index);
    }
    
    @Override
    public boolean addAll(Collection<? extends ITrackCellData> coll) {
        boolean success = super.addAll(coll);
        
        if (success) {
            notifyListeners(ListDataEvent.INTERVAL_ADDED, size() - 1, size() - 1 + coll.size());
        }
        
        return success;
    }
    
    @Override
    public boolean addAll(int index, Collection<? extends ITrackCellData> coll) {
        boolean success = super.addAll(index, coll);
        
        if (success) {
            notifyListeners(ListDataEvent.INTERVAL_ADDED, index, index + coll.size());
        }
        
        return success;
    }
    
    private void notifyListeners(int type, int i1, int i2) {
        doFilter(false);
        
        ListDataEvent evt = new ListDataEvent(this, type, i1, i2);
        
        for (ListDataListener l: dataListeners) {
            if (type == ListDataEvent.INTERVAL_ADDED) {
                l.intervalAdded(evt);
            }
            else if (type == ListDataEvent.INTERVAL_REMOVED) {
                l.intervalRemoved(evt);
            }
            else {
                l.contentsChanged(evt);
            }
        }
    }
    
    @Override
    public int getSize() {
        return filtered.size();
    }

    @Override
    public ITrackCellData getElementAt(int index) {
        return filtered.get(index);
    }

    @Override
    public void addListDataListener(ListDataListener l) {
        dataListeners.add(l);
    }

    @Override
    public void removeListDataListener(ListDataListener l) {
        dataListeners.remove(l);
    }
    
    public void setFilter(String filter) {
        if (filter == null) {
            this.filter = "";
        }
        else {
            this.filter = filter;
            doFilter(true);
        }
    }
    
    private void doFilter(boolean notify) {
        filtered.clear();
        
        for (ITrackCellData e: this) {
            if (e.getTrackName().contains(filter)) {
                filtered.add(e);
            }
        }
        
        if (notify) {
            notifyListeners(ListDataEvent.CONTENTS_CHANGED, 0, filtered.size() - 1);
        }
    }
}
